package org.dtrd.modules.patient.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dtrd.common.util.CheckUtil;
import org.dtrd.common.util.DateUtils;
import org.dtrd.common.util.StringUtil;
import org.dtrd.config.common.PathUtil;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.*;
import org.dtrd.config.wechat.api.impl.WechatApi;
import org.dtrd.config.wechat.config.WechatConstant;
import org.dtrd.config.wechat.config.WechatConstant.OfficialAccountTag;
import org.dtrd.config.wechat.entity.bean.WechatQrCodeTicket;
import org.dtrd.config.wechat.entity.bean.officialaccount.WechatOfficialAccountUserInfo;
import org.dtrd.modules.achievement.entity.bean.*;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchiveBasic;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchiveOverview;
import org.dtrd.modules.archive.service.IDtrdEntRdArchiveBasicService;
import org.dtrd.modules.archive.service.IDtrdEntRdOverviewService;
import org.dtrd.modules.archive.service.IDtrdEntRdPhysicalService;
import org.dtrd.modules.common.entity.bean.PatientListInfo;
import org.dtrd.modules.common.entity.po.DtrdViewRlGroupPatient;
import org.dtrd.modules.common.mapper.DtrdViewRlGroupPatientMapper;
import org.dtrd.modules.content.tags.service.IDtrdExtEmsYwTagsService;
import org.dtrd.modules.control.service.IDtrdEntRdSigninTargetDetailService;
import org.dtrd.modules.device.entity.bean.DeviceListInfo;
import org.dtrd.modules.device.service.IDtrdEntRdDeviceService;
import org.dtrd.modules.dict.service.IDtrdEntRdDicDistrictService;
import org.dtrd.modules.doctor.entity.po.DtrdEntRdDoctor;
import org.dtrd.modules.doctor.entity.po.DtrdEntRdDoctorTeam;
import org.dtrd.modules.doctor.service.IDtrdEntRdDoctorService;
import org.dtrd.modules.doctor.service.IDtrdEntRdDoctorTeamService;
import org.dtrd.modules.doctor.service.IDtrdRlDoctorPatientService;
import org.dtrd.modules.doctor.service.IDtrdRlDoctorTeamDoctorService;
import org.dtrd.modules.flup.entity.bean.FlupRecord;
import org.dtrd.modules.flup.service.IDtrdEntRdFlupAppointmentRecordService;
import org.dtrd.modules.organization.entity.po.DtrdEntRdOrganization;
import org.dtrd.modules.patient.entity.bean.*;
import org.dtrd.modules.patient.entity.bean.miniprogram.MiniprogramEventType;
import org.dtrd.modules.patient.entity.bean.miniprogram.PatientMiniProgramIndexInfo;
import org.dtrd.modules.patient.entity.bean.miniprogram.PatientMiniProgramLatestData;
import org.dtrd.modules.patient.entity.bean.miniprogram.PatientMiniProgramSigninStatus;
import org.dtrd.modules.patient.entity.bean.report.ReportListInfo;
import org.dtrd.modules.patient.entity.bean.report.ReportTable;
import org.dtrd.modules.patient.entity.bean.report.SigninRateLine;
import org.dtrd.modules.patient.entity.po.DtrdEntRdPatient;
import org.dtrd.modules.patient.entity.po.DtrdEntRdReport;
import org.dtrd.modules.patient.entity.request.PatientAllRequest;
import org.dtrd.modules.patient.entity.request.PatientIndexRequest;
import org.dtrd.modules.patient.entity.request.PatientRequest;
import org.dtrd.modules.patient.mapper.DtrdEntRdPatientMapper;
import org.dtrd.modules.patient.service.IDtrdEntRdPatientService;
import org.dtrd.modules.patient.service.IDtrdRlGroupPatientService;
import org.dtrd.modules.questionnaire.entity.bean.ArchiveHomePageInfo;
import org.dtrd.modules.questionnaire.entity.bean.PatientDetailInfo;
import org.dtrd.modules.questionnaire.entity.bean.QuestionnaireRdVersionDetail;
import org.dtrd.modules.questionnaire.service.IDtrdEntRdQuestionnaireDataService;
import org.dtrd.modules.questionnaire.service.IDtrdEntRdQuestionnaireRdVersionService;
import org.dtrd.modules.questionnaire.service.IDtrdEntRdQuestionnaireService;
import org.dtrd.modules.record.entity.bean.*;
import org.dtrd.modules.record.entity.po.*;
import org.dtrd.modules.record.service.*;
import org.dtrd.modules.service.entity.bean.PatientServiceIndexInfo;
import org.dtrd.modules.service.entity.bean.ServiceDetailItem;
import org.dtrd.modules.service.entity.po.DtrdRlPackagePatient;
import org.dtrd.modules.service.service.IDtrdEntRdServicePackageService;
import org.dtrd.modules.service.service.IDtrdRlPackagePatientService;
import org.dtrd.modules.shop.service.IKingdeeService;
import org.dtrd.modules.system.entity.SysUser;
import org.dtrd.modules.system.entity.bean.qiyeweixin.QwClientBaseInfo;
import org.dtrd.modules.system.service.ISysDictService;
import org.dtrd.modules.system.service.impl.SysUserServiceImpl;
import org.dtrd.modules.util.ReportUtil;
import org.dtrd.modules.util.SchemeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.IntStream;

/**
 * @author 萧
 * @date 2021-09-26 23:31:52
 **/
@Service
@DS("multi-datasource1")
@Slf4j
public class DtrdEntRdPatientServiceImpl extends ServiceImpl<DtrdEntRdPatientMapper, DtrdEntRdPatient> implements IDtrdEntRdPatientService {

    private static final String COMMA = ",";

    /**
     * 诊断结果
     */
    private static final String DIAGNOSIS = "diagnosis";
    /**
     * 医保类型
     */
    private static final String INSURANCE = "insurance";
    /**
     * 起病方式
     */
    private static final String SYMPTOMSMODE = "symptomsmode";
    /**
     * 起病症状
     */
    private static final String SYMPTOMS = "symptoms";
    /**
     * 糖尿病类型
     */
    private static final String DIABETIS_TYPE = "diabetis_type";

    @Autowired
    private IKingdeeService kingdeeService;
    @Autowired
    private ISysDictService sysDictService;
    @Autowired
    private IDtrdRlGroupPatientService groupPatientRlService;
    @Autowired
    private ISugarRecordService sugarRecordService;
    @Autowired
    private IBloodPressureRecordService bloodPressureRecordService;
    @Autowired
    private ISportRecordService sportRecordService;
    @Autowired
    private IMedicalRecordService medicalRecordService;
    @Autowired
    private IFoodRecordService foodRecordService;
    @Autowired
    private IHeightWeightRecordService heightWeightRecordService;
    @Autowired
    private IWaistlineRecordService waistlineRecordService;
    @Autowired
    private IKetoneRecordService ketoneRecordService;
    @Autowired
    private IInsulinRecordService insulinRecordService;
    @Autowired
    private ISleepRecordService sleepRecordService;

    @Autowired
    private IDtrdEntRdDeviceService deviceService;
    @Autowired
    private IDtrdEntRdFlupAppointmentRecordService flupAppointmentRecordService;
    @Autowired
    private IDtrdEntRdArchiveBasicService basicService;
    @Autowired
    private IDtrdEntRdDicDistrictService districtInfoService;
    @Autowired
    private IDtrdRlPackagePatientService packagePatientRlService;
    @Autowired
    private IDtrdEntRdServicePackageService packageService;
    @Autowired
    private IDtrdEntRdPhysicalService physicalService;
    @Autowired
    private IDtrdEntRdOverviewService overviewService;
    @Autowired
    private SysUserServiceImpl userService;
    @Autowired
    private IDtrdEntRdQuestionnaireRdVersionService questionnaireRdVersionService;
    @Autowired
    private IDtrdEntRdSigninSuggestService suggestService;
    @Autowired
    private IDtrdEntRdSigninTargetDetailService targetDetailService;
    @Autowired
    private IDtrdEntRdUplowRecordService uplowRecordService;
    @Autowired
    private DtrdViewRlGroupPatientMapper groupPatientMapper;
    @Autowired
    private IDtrdExtEmsYwTagsService tagsService;
    @Autowired
    private IDtrdViewRlCheckinRecordService checkinRecordViewService;
    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;
    @Autowired
    private IDtrdRlDoctorPatientService doctorPatientRlService;
    @Autowired
    private IDtrdEntRdDoctorService doctorService;
    @Autowired
    private IDtrdEntRdDoctorTeamService doctorTeamService;
    @Autowired
    private IDtrdRlDoctorTeamDoctorService doctorTeamRlService;

    @Autowired
    private WechatApi wechatApi;

    @Autowired
    private IDtrdEntRdQuestionnaireService questionnaireService;

    @Autowired
    private IDtrdEntRdQuestionnaireDataService questionnaireServiceData;

    @Override
    public List<Integer> getAllPatientIdList() {
        return baseMapper.getAllPatientIdList();
    }

    @Override
    public PatientInfo selectOneByCondition(PatientRequest request) {
        return null;
    }

    @Override
    public PatientInfo selectByPatientId(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper = generateBaseLambdaQuery().eq(DtrdEntRdPatient::getDataId, patientId);
        return selectOne(queryWrapper);
    }

    @Override
    public DtrdEntRdPatient selectPoByPatientId(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper = generateBaseLambdaQuery().eq(DtrdEntRdPatient::getDataId, patientId);
        return selectOnePo(queryWrapper);
    }

    @Override
    public DtrdEntRdPatient getPatientInfoByUnionId(String unionid) {
        LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper = generateBaseLambdaQuery();
        queryWrapper.eq(DtrdEntRdPatient::getWxUnionid, unionid);
        return selectOnePo(queryWrapper);
    }

    @Override
    public boolean onScanDoctorQrCode(Integer userId, String qrcodeUrl) {
        DtrdEntRdDoctor doctor = doctorService.getDoctorByQrcodeUrl(qrcodeUrl);
        if (doctor != null) {
            return doctorPatientRlService.saveOrUpdateDoctorPatientRelation(doctor.getDataId(), userId, DoctorPatientRelationType.ADD_BY_PATIENT_SCAN_XCX.getType());
        }
        return false;
    }

    @Override
    public DtrdEntRdPatient createRecordByToolsId(String openid, String unionid) {
        DtrdEntRdPatient patient = new DtrdEntRdPatient().init();
        patient.setWxToolsOpenid(openid);
        patient.setWxUnionid(unionid);
        log.info("DtrdEntRdPatientServiceImpl.createRecordByToolsId.[openid, unionid] openId = {}, unionid = {}", openid, unionid);
        save(patient);
        return patient;
    }

    @Override
    public void updatePatientToolsInfo(Integer dataId, String unionid, String openid) {
        DtrdEntRdPatient po = getById(dataId);
        po.setWxUnionid(unionid);
        po.setWxToolsOpenid(openid);
        updateById(po);
    }

    @Override
    public DtrdEntRdPatient selectByUnionIdOrOpenIdOrWxOaOpenId(String unionId, String wxOaOpenId, String openId) {
        return baseMapper.selectByUnionIdOrOpenIdOrWxOaOpenId(unionId, wxOaOpenId, openId);
    }

    @Override
    public PatientInfo selectByMobile(String mobile) {
        LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper = generateBaseLambdaQuery().eq(DtrdEntRdPatient::getPatientsMobile, mobile);
        return selectOne(queryWrapper);
    }

    /**
     * 重载save方法，增加患者注册事件与二维码生成事件
     *
     * @param entity
     * @return
     */
    @Override
    public boolean save(DtrdEntRdPatient entity) {
        boolean save = super.save(entity);
        if (save) {
            if (entity.getDoctorId() != null) {
                doctorPatientRlService.saveOrUpdateDoctorPatientRelation(entity.getDoctorId(), entity.getDataId(), DoctorPatientRelationType.ADD_BY_OMS.getType());
                sendPatientRegisterEvent(entity.getDataId(), entity.getPatientsName(), entity.getDoctorId());
            }
            if (StrUtil.isNotBlank(entity.getPatientsMobile())) {
                sendQrCodeGenerateEvent(entity, true);
            }
        }
        return save;
    }

    /**
     * 发送患者注册事件给医生
     *
     * @param patientId
     * @param patientsName
     * @param doctorId
     */
    private void sendPatientRegisterEvent(Integer patientId, String patientsName, Integer doctorId) {
        log.info("DtrdEntRdPatientServiceImpl.sendPatientRegisterEvent.[dataId = {}, patientsName ={}, doctorId={}", patientId, patientsName, doctorId);
        if (doctorId != null) {
            String chatRoomId = doctorPatientRlService.getChatroomIdByPatientId(patientId, doctorId);
            if (chatRoomId == null) {
                // 无医患关联 无须推送
                log.info("DtrdEntRdPatientServiceImpl.sendPatientRegisterEvent.[patientId, patientsName, doctorId] chatroomid is null");
                return;
            }
            DtrdEntRdDoctor doctor = doctorService.getById(doctorId);
            if (doctor == null || StrUtil.isBlank(doctor.getWxOaOpenid())) {
                log.info("DtrdEntRdPatientServiceImpl.sendPatientRegisterEvent.[dataId, patientsName, doctorId] doctorId = " + doctorId + "； openId=" + doctor.getWxOaOpenid() + ";  医生信息为空 或者医生openID为空");
                return;
            }
            wechatApi.sendPatientRegisterMsg(patientsName, DateUtils.formatDate(DateUtils.datetime_sdf_wz.get().toPattern()), "", PathUtil.getChatroomUrl(USER_CATEGORY.USER_DOCTOR.getUser(), doctorId + "", chatRoomId), doctor.getWxOaOpenid());
        } else {
            log.info("DtrdEntRdPatientServiceImpl.sendPatientRegisterEvent.[patientId, patientsName, doctorId] doctor is null ");
        }
    }

    /**
     * 发送患者二维码生成事件
     *
     * @param patient
     * @return
     */
    private WechatQrCodeTicket sendQrCodeGenerateEvent(DtrdEntRdPatient patient, boolean saveInside) {
        WechatQrCodeTicket userQrCodeTicket = wechatApi.createUserQrCode(patient.getDataId(), QRCODE_TYPE.PATIENT.getType(), null);
        String userQrCode = userQrCodeTicket != null ? userQrCodeTicket.getQrCodeUrl() : null;
        log.info("DtrdEntRdPatientServiceImpl.sendQrCodeGenerateEvent.[patientId] " + userQrCodeTicket);
        if (userQrCode != null && saveInside) {
            patient.setWxOaQrcodeUrl(userQrCode);
            patient.setWxOaQrcodeSourceUrl(userQrCodeTicket.getUrl());
            updateById(patient);
        }
        return userQrCodeTicket;
    }

    @Override
    public PatientInfo createPatientByWechatUserInfo(WechatOfficialAccountUserInfo userInfo) {
        DtrdEntRdPatient patient = new DtrdEntRdPatient().init();
        patient = patient.parseFromDTO(userInfo);
        save(patient);
        return new PatientInfo().parseFromPO(patient);
    }

    @Override
    public DtrdEntRdPatient createPatientByOpenIdAndUnionid(String openid, String unionid) {
        DtrdEntRdPatient patient = new DtrdEntRdPatient().init();
        patient.setWxOpenid(openid);
        patient.setWxUnionid(unionid);
        log.info("DtrdEntRdPatientServiceImpl.createPatientByOpenIdAndUnionid.[openid] openId = {}, unionid = {}", openid, unionid);
        save(patient);
        return patient;
    }

    @Override
    public DtrdEntRdPatient createPatientByOaOpenIdAndUnionid(String openid, String unionid) {
        DtrdEntRdPatient patient = new DtrdEntRdPatient().init();
        patient.setWxOaOpenid(openid);
        patient.setWxUnionid(unionid);
        log.info("DtrdEntRdPatientServiceImpl.createPatientByOfficialAccountsOpenIdAndUnionid.[openid] officialAccountOpenId = {}, unionid = {}", openid, unionid);
        save(patient);
        return patient;
    }

    @Override
    public boolean updatePatientInfo(PatientInfo patientInfo, boolean fromWxApp) {
        DtrdEntRdPatient po = getById(patientInfo.getDataId());
        if (po == null) {
            return false;
        }
        // 小程序调用
        if (fromWxApp) {
            po.setPatientsMobile(patientInfo.getPatientsMobile());
            po.setPatientsNickname(patientInfo.getPatientsNickname());
            if (po.getPatientsName() == null) {
                po.setPatientsName(patientInfo.getPatientsNickname());
            }
            po.setPatientsImg(patientInfo.getPatientsImg());
        } else {
            po.parseFromDto(patientInfo);
            // 更新糖尿病类型
            if (patientInfo.getPatientsDiabetisType() != null) {
                overviewService.updatePatientDiabetesType(patientInfo.getDataId(), patientInfo.getPatientsDiabetisType());
            }
            // 保存患者身高体重
            if (!patientInfo.getUpdateDiabetes()) {
                physicalService.updatePatientHeightOrWeight(patientInfo.getDataId(), patientInfo.getPatientsHeight(), patientInfo.getPatientsWeight());
            }
        }

        return updateById(po);
    }

    @Override
    public boolean isValidPatientId(Integer patientId) {
        return baseMapper.hasPatientId(patientId);
    }

    @Override
    public IPage<PatientPageInfo> getPatientListByGroupId(Integer pageNum, Integer pageSize, Integer groupId) {
        IPage<PatientPageInfo> page = new Page<>(pageNum, pageSize);
        if (groupId == 0) {
            page = baseMapper.selectPageNoGroup(page);
        } else {
            page = baseMapper.selectPageByGroupId(page, groupId);
        }
        return page;
    }

    /**
     * 关联手机号到指定账号，若手机号已存在则将patientID对应账户的openID写入手机账户,并返回手机账户id
     *
     * @param patientId
     * @param mobile
     * @return
     */
    @Override
    public Integer bindMobileToPatient(Integer patientId, String mobile) {
        DtrdEntRdPatient patientById = getById(patientId);
        log.info("DtrdEntRdPatientServiceImpl.bindMobileToPatient.[patientId, mobile] query By id patientId=" + patientId + "; info=" + patientById);
        if (patientById != null) {
            DtrdEntRdPatient patient = baseMapper.selectRecordByMobile(mobile);
            log.info("DtrdEntRdPatientServiceImpl.bindMobileToPatient.[patientId, mobile] query by mobile mobile =" + mobile + "; info=" + patient);
            if (patient != null && !patient.getDataId().equals(patientId)) {
                // 手机号码已存在 将微信 openId写入手机账户 并删除原有账户
                if (StrUtil.isBlank(patient.getWxOpenid())) {
                    patient.setWxOpenid(patientById.getWxOpenid());
                }
                patient.setWxUnionid(patientById.getWxUnionid());
                if (StrUtil.isBlank(patient.getWxOaOpenid())) {
                    patient.setWxOaOpenid(patientById.getWxOaOpenid());
                }
                if (StrUtil.isBlank(patient.getPatientsNickname())) {
                    patient.setPatientsNickname(patientById.getPatientsNickname());
                }
                if (StrUtil.isBlank(patient.getPatientsName())) {
                    patient.setPatientsName(patientById.getPatientsName());
                }
                if (patient.getPatientsSex() == null) {
                    patient.setPatientsSex(patientById.getPatientsSex());
                }
                if (StrUtil.isBlank(patient.getPatientsImg())) {
                    patient.setPatientsImg(patientById.getPatientsImg());
                }
                WechatQrCodeTicket wechatQrCodeTicket = sendQrCodeGenerateEvent(patient, false);
                log.info("DtrdEntRdPatientServiceImpl.bindMobileToPatient.[patientId, mobile] wechatQrCodeTicket=" + wechatQrCodeTicket);
                patient.setWxOaQrcodeUrl(Optional.ofNullable(wechatQrCodeTicket).map(WechatQrCodeTicket::getQrCodeUrl).orElse(null));
                patient.setWxOaQrcodeSourceUrl(Optional.ofNullable(wechatQrCodeTicket).map(WechatQrCodeTicket::getUrl).orElse(null));
                patientId = patient.getDataId();
                // 删除原有账户
                baseMapper.deletePatientRecord(patientById.getDataId());
            } else {
                // patientId账号手机号码不存在 将手机号码写入
                log.info("DtrdEntRdPatientServiceImpl.bindMobileToPatient.[patientId, mobile=" + patientById.getPatientsMobile() + ";CheckUtil.isEmpty(patientInfoById.getPatientsMobile())=" + CheckUtil.isEmpty(patientById.getPatientsMobile()));
                patientById.setPatientsMobile(mobile);
                patient = patientById;
            }
            if (patient != null) {
                log.info("DtrdEntRdPatientServiceImpl.bindMobileToPatient.[patientId, mobile] 更新用户信息 id=" + patient.getDataId() + ";mobile=" + patient.getPatientsMobile());
                saveOrUpdate(patient);
                if (StrUtil.isNotBlank(patient.getWxOaOpenid())) {
                    Integer tagId = OfficialAccountTag.USER_TAG_ID.getTag();
                    wechatApi.bindingTag(tagId, WechatConstant.OfficialAccountTag.getMutexTagIdList(tagId), patient.getWxOaOpenid());
                }
            }
            return patientId;
        }
        return null;
    }

    /**
     * 同步企业微信客户信息至本地
     *
     * @param external_contact
     * @param mobile
     * @return
     */
    @Override
    public Integer syncQwClientInfo(QwClientBaseInfo external_contact, String mobile) {
        DtrdEntRdPatient po = baseMapper.selectRecordByMobile(mobile);
        if (po == null) {
            po = new DtrdEntRdPatient().init();
            po.setPatientsMobile(mobile);
        }
        if (po.getPatientsImg() == null) {
            po.setPatientsImg(external_contact.getAvatar());
        }
        if (po.getPatientsName() == null) {
            po.setPatientsName(external_contact.getName());
        }
        if (po.getPatientsSex() == null) {
            po.setPatientsSex(external_contact.getGender());
        }
        saveOrUpdate(po);
        log.info("DtrdEntRdPatientServiceImpl.syncQwClientInfo.[external_contact, mobile] after saveOrUpdate po.getDataId() = " + po.getDataId());
        return po.getDataId();
    }

    @Override
    public PatientPublicAccountInfo getPatientPublicAccountInfo(Integer patientId) {
        DtrdEntRdPatient patient = getById(patientId);
        return Optional.ofNullable(patient).map(p -> {
            PatientPublicAccountInfo patientPublicAccountInfo = new PatientPublicAccountInfo().parseFromPO(p);
            // 地址
            Integer cityId = p.getPatientsCityId();
            Integer provinceId = p.getPatientsProvinceId();
            StringJoiner joiner = new StringJoiner("");
            if (provinceId != null) {
                String provinceName = districtInfoService.getDistrictNameByAreaId(provinceId);
                joiner.add(provinceName);
            }
            if (cityId != null && !Objects.equals(provinceId, cityId)) {
                String cityName = districtInfoService.getDistrictNameByAreaId(cityId);
                joiner.add(cityName);
            }
            patientPublicAccountInfo.setLocation(joiner.toString());
            // 血糖 / 糖化血红蛋白 / 糖尿病诊断
            DtrdEntRdArchiveOverview overview = overviewService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class).eq(DtrdEntRdArchiveOverview::getPatientId, patientId));
            if (overview != null) {
                patientPublicAccountInfo = patientPublicAccountInfo.parseFromPO(overview);
            }
            return patientPublicAccountInfo;
        }).orElse(null);
    }

    @Override
    public PatientPublicAccountInfo getPatientPublicAccountInfo(String phoneNumber) {
        DtrdEntRdPatient patient = getOne(Wrappers.lambdaQuery(DtrdEntRdPatient.class).eq(DtrdEntRdPatient::getPatientsMobile, phoneNumber));
        return Optional.ofNullable(patient).map(p -> getPatientPublicAccountInfo(p.getDataId())).orElse(null);
    }

    // TODO 方法设计待修改 肖 2022-03-26 14:13:36
    @Override
    public PatientHomePageInfo getPatientHomePageInfo(Integer patientId) {
        PatientHomePageInfo patientStatisticInfo = new PatientHomePageInfo();
        long getPatientHomePageInfoStartTime = System.currentTimeMillis();
        //region 分组名称
        String groupName = groupPatientRlService.getGroupName(patientId);
        // 怎么都有个未分组
        patientStatisticInfo.setGroupName(groupName);
        //endregion
        //region 服务名称及服务开始/终止时间
        PatientServiceIndexInfo serviceIndexInfo = packagePatientRlService.getPatientServiceIndexInfo(patientId);
        if (serviceIndexInfo != null) {
            patientStatisticInfo.parseFromDTO(serviceIndexInfo);
        }
        //endregion
        //region 今日血糖
        Date today = DateUtils.getDateYMD();
        PatientDailySugar dailySugar = sugarRecordService.getPatientDailySugar(patientId, today);
        if (dailySugar != null) {
            patientStatisticInfo.parseFromDTO(dailySugar);
        }
        //endregion
        //region 复诊状态
        FlupRecord flupRecord = flupAppointmentRecordService.getPatientFlupRecordStartOfThisWeek(patientId);
        if (flupRecord != null) {
            patientStatisticInfo.parseFromDTO(flupRecord);
        } else {
            patientStatisticInfo.setFlupStatusNum(Constant.FlupStatus.NoAppointment.getStatus());
            patientStatisticInfo.setFlupStatus("暂无预约记录");
        }
        //endregion
        //region 打卡天数/次数/分数 打卡分数=打卡率
        PatientSigninStatusBean patientSigninStatus = signinRecordService.getPatientIndexSignStatus(patientId);
        if (patientSigninStatus != null) {
            patientStatisticInfo.parseFromDTO(patientSigninStatus);
        }
        // 打卡分数
        Map<Date, Integer> rateMap = signinRecordService.getSigninFinishedRateMap(patientId, today, today);
        if (MapUtil.isNotEmpty(rateMap)) {
            patientStatisticInfo.setSigninScore(rateMap.get(today));
        }
        //endregion
        //region 今日饮食打卡
        DailySigninDietStatus signinDietStatus = foodRecordService.getPatientDailySigninDietStatus(patientId, today);
        if (signinDietStatus != null) {
            patientStatisticInfo.parseFromDTO(signinDietStatus);
        }
        //endregion
        //region 患者信息完成百分比
        Integer infoPercent = basicService.getPatientArchiveInfoPercent(patientId);
        if (infoPercent != null) {
            patientStatisticInfo.setInfoCompletePercentage(infoPercent);
        }
        //endregion
        //region 查询患者标签
        List<String> tags = tagsService.getPatientTags(patientId);
        if (CollectionUtil.isNotEmpty(tags)) {
            patientStatisticInfo.setTags(tags);
        }
        //endregion
        //region 上下限信息
        ValueUplowBean upLowRecord = uplowRecordService.getSugarValueUpLowRecord(null, patientId);
        patientStatisticInfo.setUplowInfo(upLowRecord);
        //endregion
        long getPatientHomePageInfoEndTime = System.currentTimeMillis();
        log.info("----------查询患者首页信息结束，共耗时：{}ms, 患者id: {}----------", getPatientHomePageInfoEndTime - getPatientHomePageInfoStartTime, patientId);
        return patientStatisticInfo;
    }

    @Override
    public void registerDefaultPatient(String phone) {
        DtrdEntRdPatient patient = new DtrdEntRdPatient();
        // 设置默认名字
        patient.setPatientsName(Constant.DEFAULT_NAME);
        patient.setPatientsMobile(phone);
        save(patient);
    }

    @Override
    public boolean saveOrUpdatePatientInfo(PatientPublicAccountInfo patientPublicAccountInfo) {
        Integer patientId = patientPublicAccountInfo.getPatientId();
        // 更新 patient 表信息
        DtrdEntRdPatient patient = getOne(Wrappers.lambdaQuery(DtrdEntRdPatient.class).eq(DtrdEntRdPatient::getDataId, patientId));
        patient.parseFromDTO(patientPublicAccountInfo);
        boolean result = updateById(patient);
        // 更新糖尿病概况数据
        LambdaQueryWrapper<DtrdEntRdArchiveOverview> wrapper = Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class).eq(DtrdEntRdArchiveOverview::getPatientId, patientId);
        DtrdEntRdArchiveOverview overview = overviewService.getOne(wrapper);
        if (overview == null) {
            DtrdEntRdArchiveOverview po = new DtrdEntRdArchiveOverview().parseFromDTO(patientPublicAccountInfo);
            po.setPatientId(patientId);
            overviewService.save(po);
        } else {
            overview = overview.parseFromDTO(patientPublicAccountInfo);
            overviewService.updateById(overview);
        }
        // 更新 sysUser 表信息
        String mobile = patient.getPatientsMobile();
        SysUser sysUser = userService.getUserByPhone(mobile);
        if (sysUser != null) {
            sysUser.parseFromPO(patient);
            userService.updateById(sysUser);
        }
        return result;
    }

    @Override
    public boolean checkPatientMobile(String mobile, Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdPatient> wrapper = Wrappers.lambdaQuery(DtrdEntRdPatient.class).eq(DtrdEntRdPatient::getPatientsMobile, mobile);
        DtrdEntRdPatient patient = getOne(wrapper);
        return patient == null || patient.getDataId().equals(patientId);
    }

    @Override
    public ArchiveHomePageInfo getPatientArchiveHomePageInfo(Integer patientId) {
        ArchiveHomePageInfo pageInfo = new ArchiveHomePageInfo(patientId);
        // 基础信息
        DtrdEntRdPatient patient = getById(patientId);
        if (patient == null) {
            return pageInfo;
        }
        pageInfo.setBasicInfoIsFinished(patient.getIsFinished());
        // 详情信息
        PatientDetailInfo detailInfo = questionnaireRdVersionService.getPatientDetailInfo(patientId);
        Optional.of(detailInfo).ifPresent(d -> pageInfo.setDetailInfoIsFinished(d.getIsFinished()));
        // 逆转问卷
        QuestionnaireRdVersionDetail reversion = questionnaireRdVersionService.getQuestionnaireReversion(patientId);
        // reversion 在保存基本信息的时候已经进行创建，所以最后的结果一定是判定为true，所以只需要判定填写已确诊的情况才需补充信息
        Optional.ofNullable(reversion).ifPresent(r -> pageInfo.setReversionResearchIsFinished(
                2 == reversion.getDiabetesDiagnosis() &&
                        reversion.getDiabetesComplication() == null ?
                        Constant.UN_FINISHED : Constant.FINISHED));
        // 生活方式问卷
        Integer lastAnswerQuestionId = questionnaireServiceData.getLastAnswerQuestionId("life_way", patientId);
        Integer questionLastOneId = questionnaireService.getLastQuestion("life_way");
        Boolean isFinished = Objects.equals(lastAnswerQuestionId, questionLastOneId);
        pageInfo.setLifewayResearchIsFinished(isFinished ? 1 : 0);
//        QuestionnaireLifewayDetail lifeway = lifewayService.getQuestionnaireRdLifeway(patientId);
//        Optional.ofNullable(lifeway).ifPresent(l -> pageInfo.setLifewayResearchIsFinished(Constant.FINISHED));
        // TODO 逆转方式问卷
        return pageInfo;
    }

    @Override
    public void updatePatientUnionIdAndWxOpenid(Integer patientId, String unionid, String openid) {
        baseMapper.updatePatientUnionIdAndWxOpenid(patientId, unionid, openid);
    }

    @Override
    public void updatePatientUnionIdAndWxOaOpenid(Integer patientId, String unionid, String openid) {
        baseMapper.updatePatientUnionIdAndWxOaOpenid(patientId, unionid, openid);
    }

    @Override
    public PatientMiniProgramIndexInfo getPatientMiniProgramIndexInfo(Integer patientId) {
        PatientMiniProgramIndexInfo indexInfo = new PatientMiniProgramIndexInfo();
        DtrdEntRdPatient patient = getById(patientId);
        // 患者基础信息(是否购买服务都会返回)
        indexInfo = indexInfo.parseFromPO(patient);
        PatientMiniProgramLatestData data = null;
        // 最新血糖时间和值
        List<DeviceListInfo> deviceList = deviceService.getBindDevice(patientId);
        if (CollectionUtil.isEmpty(deviceList)) {
            // 未绑定设备  提示绑定
            data = new PatientMiniProgramLatestData("立即绑定血糖仪", "https://images-gz.oss-cn-guangzhou.aliyuncs.com/icon/bindtool.png");
            data.setEventType(new MiniprogramEventType(MiniProgramEventType.jump_localpage.name(), "/pages/scan/scan?userid=" + patientId));
            indexInfo.setDeviceBindInfo(data);
        } else {
            DtrdEntRdSigninSugarValue sugarValueLatest = sugarRecordService.getSugarValueLatest(patientId);
            if (sugarValueLatest != null) {
                data = new PatientMiniProgramLatestData().parseFromPO(sugarValueLatest);
                // 设置血糖状况
                data.setStatus(SchemeUtil.compareSugarStatus(sugarValueLatest.getSugarValueSugarValue(), sugarValueLatest.getSugarValueTimeTypeId(), patientId));
            } else {
                // 无最新血糖 提示记血糖
                data = new PatientMiniProgramLatestData("暂无最新测量数据", "https://images-gz.oss-cn-guangzhou.aliyuncs.com/icon/index_none.png");
                data.setEventType(new MiniprogramEventType(MiniProgramEventType.jump_localpage.name(), "/pages/checkin/checkin?userid=" + patientId + "&recordType=" + RecordType.SUGAR.getType()));
            }
            indexInfo.setLatestData(data);
        }
        // 关联团队前移 肖 2022-06-07 17:12:52
        Integer doctorId = doctorPatientRlService.getDoctorIdByPatientId(patientId);
        if (doctorId != null) {
            DtrdEntRdDoctorTeam doctorTeam = doctorTeamService.getDoctorTeamByDoctorId(doctorId);
            if (doctorTeam != null) {
                indexInfo.setTitle(doctorTeam.getName());
            }
            indexInfo.setDoctorId(doctorId);
            indexInfo.setDoctorInfos(doctorTeamRlService.getTeamDoctorList(doctorId));
            String orgCode = doctorService.getDoctorOrgCodeById(doctorId);
            if (StrUtil.isNotBlank(orgCode)) {
                indexInfo.setOrgDetailUrl(PathUtil.getOrgDetailUrl(orgCode));
            }
        }

        // 服务状况
        DtrdRlPackagePatient patientPackage = packagePatientRlService.getLatestPatientPackage(patientId);
        // region 未购买服务
        // 没有服务返回基础信息(姓名和标题(默认毅瑭科技))
        if (patientPackage == null) {
//            如果用户没有最新的服务包，查看是否有待服务的服务包
            patientPackage = packagePatientRlService.getAllStatusPatientPackage(patientId);
            if (patientPackage != null && patientPackage.getStatus().equals(Constant.PackageServiceStatus.WAIT_TO_SERVICE.getType())) {
                indexInfo.setServiceStatus(patientPackage.getStatus());
            }
            return indexInfo;
        }
        // 未购买服务返回状态和基础信息
//        if (patientPackage.getStatus().equals(Constant.PackageServiceStatus.WAIT_TO_SERVICE.getType())) {
//            indexInfo.setServiceStatus(patientPackage.getStatus());
//            return indexInfo;
//        }
        // endregion
        // region 已购买服务
        // 设置服务包id
        indexInfo.setPackageId(patientPackage.getDataId());
        // 设置服务状态
        Integer packageStatus = patientPackage.getStatus();
        indexInfo.setServiceStatus(packageStatus);
        // 服务中和已完成状态下返回服务团队
//        if ((packageStatus.equals(Constant.PackageServiceStatus.SERVICING.getType()) || packageStatus.equals(Constant.PackageServiceStatus.FINISHED.getType())) && doctorId != null) {
//            indexInfo.setDoctorInfos(doctorTeamRlService.getTeamDoctorList(doctorId));
//        }

        // 设置建议
        List<SigninSuggestBean> suggests = suggestService.getSuggestByPatientIdAndTypes(patientId, Constant.SuggestType.MEDICAL.getType(), Constant.SuggestType.DIET.getType(), Constant.SuggestType.INSULIN.getType(), Constant.SuggestType.SPORT.getType());
        if (CollectionUtil.isNotEmpty(suggests)) {
            indexInfo.setSuggests(suggests);
        }
        // 控制目标
        List<WeekRecordSummary> recordSummaries = targetDetailService.getWeekSummary(patientId);
        if (recordSummaries != null) {
            indexInfo.setTargets(recordSummaries);
        }
        // 打卡状况
        PatientMiniProgramSigninStatus signStatus = signinRecordService.getPatientSignStatus(patientId);
        indexInfo.setSigninStatus(signStatus);
        // 未完成服务项3条
        List<ServiceDetailItem> services = packageService.getThreeUnFinishedServiceDetailLatest(patientId);
        if (CollectionUtil.isNotEmpty(services)) {
            indexInfo.setServices(services);
        }
        // 打卡完成率
        Integer finishedRate = signinRecordService.getSigninFinishedThisWeek(patientId);
        if (finishedRate != null) {
            indexInfo.setSigninFinishedRate(finishedRate + "%");
        }
        // 打卡达标率
        Integer rate = uplowRecordService.getSugarReachStandardRateThisWeek(patientId);
        if (rate != null) {
            indexInfo.setSigninReachStandardRate(rate + "%");
        }
        Integer status = signStatus.getStatus();
        // 今日打卡
        List<PatientSigninRecord> dataList = signinRecordService.getPatientSigninRecords(patientId, DateUtils.formatDate());
        if (dataList != null && status.equals(Constant.PatientSigninStatus.USING.getType())) {
            indexInfo.setPatientSigninRecords(dataList);
        }
        // endregion
        return indexInfo;
    }

    @Override
    public void updatePatientInfoByWechatUserInfo(WechatOfficialAccountUserInfo userInfo, Integer patientId) {
        DtrdEntRdPatient patient = getById(patientId);
        if (patient.getPatientsSex() == null) {
            patient.setPatientsSex(StringUtil.StrTrimInt(userInfo.getSex()) == 0 ? Sex.MAN.getType() : userInfo.getSex());
        }
        if (StrUtil.isBlank(patient.getPatientsName())) {
            patient.setPatientsName(userInfo.getNickname());
        }
        patient.setWxOaOpenid(userInfo.getOpenid());
        if (patient.getWxUnionid() == null) {
            patient.setWxUnionid(userInfo.getUnionid());
        }
        if (StrUtil.isBlank(patient.getPatientsProvinceName())) {
            patient.setPatientsProvinceName(userInfo.getProvince());
        }
        if (StrUtil.isBlank(patient.getPatientsCityName())) {
            patient.setPatientsCityName(userInfo.getCity());
        }
        if (StrUtil.isBlank(patient.getPatientsImg())) {
            patient.setPatientsImg(userInfo.getHeadimgurl());
        }
        log.info("DtrdEntRdPatientServiceImpl.updatePatientInfoByWechatUserInfo.[userInfo{}, patientId = {}", patient, patientId);
        updateById(patient);
    }

    @Override
    public IPage<PatientListInfo> pagePatientInfo(Page<DtrdViewRlGroupPatient> page, String phone, String name, Integer groupId, Integer status, Date startDate, Date endDate, List<Integer> patientIds, String patientName, String patientMobile) {
        return groupPatientMapper.listPatientInfo(page, phone, name, groupId, status, startDate, endDate, patientIds, patientName, patientMobile);
    }

    @Override
    public IPage<PatientListInfo> selectPatientInfo(Page<DtrdViewRlGroupPatient> page, List<Integer> doctorIdList, Integer groupId, Integer status, Date startDate, Date endDate, List<Integer> patientIds, String patientName, String name, String patientMobile, String phone) {
        log.info("DtrdEntRdPatientServiceImpl.selectPatientInfo.[page, doctorIdList=" + doctorIdList + ", groupId=" + groupId + ", status=" + status + ", startDate=" + startDate + ", endDate=" + endDate + ", patientIds=" + patientIds + ", patientName=" + patientName + " ; wrapperValue(patientName) = " + wrapperValue(patientName) + ", name=" + name + ", patientMobile=" + patientMobile + ", phone=" + phone);
        return groupPatientMapper.selectPatientInfo(page, doctorIdList, groupId, status, startDate, patientIds, wrapperValue(patientName), wrapperValue(name), wrapperValue(patientMobile), wrapperValue(phone));
    }

    private String wrapperValue(String value) {
        if (value != null) {
            value = value.trim();
        }

        return StringUtils.isBlank(value) ? null : value;
    }

    /**
     * @param request
     * @return
     * @deprecated use V3
     */
    @Override
    public PatientIndexFormInfo getPatientIndexFormInfo(PatientIndexRequest request) {
        Integer patientId = request.getPatientId();
        PatientIndexFormInfo formInfo = new PatientIndexFormInfo();
        //region 打卡率和达标率
        Date startDate = request.getStartDate();
        Date endDate = request.getEndDate();
        SigninRateLine rate = getFinishedAndReachStandardRate(patientId, startDate, endDate);
        formInfo.setSigninRateLine(rate);
        log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request] formInfo.getSigninRecords()=" + formInfo.getSigninRecords());
        //endregion
        //region 当日打卡
        Date queryDate = request.getQueryDate();
        String startDateStr = DateUtil.formatDate(queryDate);

        List<DailyGroupCheckinRecord> records = checkinRecordViewService.getCheckinRecords(patientId, startDateStr, startDateStr, true);
        log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request] startDate=" + startDateStr + "; records=" + (records == null ? " is null " : records.size()) + "; formInfo.setSigninRecords=" + (formInfo.getSigninRecords() == null ? " null " : formInfo.getSigninRecords()));
        if (CollectionUtil.isNotEmpty(records)) {
            DailyGroupCheckinRecord record = records.get(0);
//            // 将 体重 转换成 bmi
//            String weightStr = record.getK22();
//            if (StrUtil.isNotBlank(weightStr)) {
//                Float bmi = heightWeightRecordService.getPatientBmi(patientId, queryDate);
//                if (bmi != null) {
//                    record.setK22(bmi + "");
//                    record.setK22PlanState(SigninItemPlanStatus.NORMAL.getType());
//                }
//            }
            formInfo.setSigninRecords(record);
        } else {
            SigninRecord signinRecord = signinRecordService.getSigninRecordByPatientIdAndDate(patientId, startDateStr);
            if (signinRecord != null && CollectionUtil.isNotEmpty(signinRecord.getSignInActionList())) {
                List<SignInAction> actionList = signinRecord.getSignInActionList();
                DailyGroupCheckinRecord record = new DailyGroupCheckinRecord();
                record.setPatientId(patientId);
                record.setRecordDate(startDateStr);
                String NOPLAN = "-";
                actionList.stream()
                        .filter(action -> StringUtils.isEmpty(action.getStarttime()) || StringUtils.isEmpty(action.getEndtime()))
                        .forEach(po -> {
                            // 过滤得到未设置的打卡项
                            Constant.RecordType recordType = Constant.RecordType.valueOf(po.getRecordType());
                            Integer subType = po.getSubType();
                            if (recordType != null) {
                                switch (recordType) {
                                    case SUGAR: {
                                        if (subType == Constant.SugarRecordType.BEFOREBREAKFAST.getType()) {
                                            record.setK1(NOPLAN);
                                            record.setK1PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.AFTERBREAKFAST.getType()) {
                                            record.setK2(NOPLAN);
                                            record.setK2PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.BEFORELUNCH.getType()) {
                                            record.setK3(NOPLAN);
                                            record.setK3PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.AFTERLUNCH.getType()) {
                                            record.setK4(NOPLAN);
                                            record.setK4PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.BEFOREDINNER.getType()) {
                                            record.setK5(NOPLAN);
                                            record.setK5PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.AFTERDINNER.getType()) {
                                            record.setK6(NOPLAN);
                                            record.setK6PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.EARLYMORNING.getType()) {
                                            record.setK7(NOPLAN);
                                            record.setK7PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.SugarRecordType.BEFORESLEEP.getType()) {
                                            record.setK8(NOPLAN);
                                            record.setK8PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        }
                                    }
                                    break;
                                    case BLOOD_PRESSURE: {
                                        if (subType == Constant.BloodPressureRecordType.MORNING.getType()) {
                                            record.setK25(NOPLAN);
                                            record.setK25PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                            record.setK26(NOPLAN);
                                            record.setK26PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                            record.setK27(NOPLAN);
                                            record.setK27PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.BloodPressureRecordType.EVENING.getType()) {
                                            record.setK28(NOPLAN);
                                            record.setK29(NOPLAN);
                                            record.setK30(NOPLAN);
                                            record.setK28PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                            record.setK29PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                            record.setK30PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        }
                                    }
                                    break;
                                    case SPORT:
                                        record.setK12(NOPLAN);
                                        record.setK12PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        record.setK12Describe(NOPLAN);
                                        break;
                                    case MEDICAL: {
                                        if (subType == Constant.MedicalRecordType.MORNING.getType()) {
                                            record.setK13Describe(NOPLAN);
                                            record.setK13PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
                                            record.setK14Describe(NOPLAN);
                                            record.setK14PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
                                            record.setK15Describe(NOPLAN);
                                            record.setK15PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
                                            record.setK16Describe(NOPLAN);
                                            record.setK16PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        }
                                    }
                                    break;
                                    case DIET: {
                                        if (subType == Constant.FoodRecordType.BREAKFAST.getType()) {
                                            record.setK9(NOPLAN);
                                            record.setK9Describe(NOPLAN);
                                            record.setK9PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.FoodRecordType.LUNCH.getType()) {
                                            record.setK10(NOPLAN);
                                            record.setK10Describe(NOPLAN);
                                            record.setK10PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.FoodRecordType.DINNER.getType()) {
                                            record.setK11(NOPLAN);
                                            record.setK11Describe(NOPLAN);
                                            record.setK11PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        }
                                    }
                                    break;
                                    case WEIGHT:
                                        record.setK22(NOPLAN);
                                        record.setK22PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        break;
                                    case WAIST:
                                        record.setK24(NOPLAN);
                                        record.setK24PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        break;
                                    case KETONE:
                                        record.setK23(NOPLAN);
                                        record.setK23PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        break;
                                    case INSULIN: {
                                        if (subType == Constant.InsulinRecordType.MORNING.getType()) {
                                            record.setK17Describe(NOPLAN);
                                            record.setK17PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
                                            record.setK18Describe(NOPLAN);
                                            record.setK18PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
                                            record.setK19Describe(NOPLAN);
                                            record.setK19PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
                                            record.setK20Describe(NOPLAN);
                                            record.setK20PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        }
                                    }
                                    break;
                                    case SLEEP:
                                        record.setK21(NOPLAN);
                                        record.setK21PlanState(SigninItemPlanStatus.NOPLAN.getType());
                                        log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request]  sleep k21=" + record.getK21());
                                        break;
                                    default:
                                        break;
                                }
                            }
                        });
                record.setK7(NOPLAN);
                record.setK7PlanState(SigninItemPlanStatus.NOPLAN.getType());
                formInfo.setSigninRecords(record);
                log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request] getCheckinRecords is empty query from getSigninRecordByPatientIdAndDate  " + "; formInfo.setSigninRecords=" + (formInfo.getSigninRecords() == null ? " null " : formInfo.getSigninRecords()));
            }
        }

        //endregion
        //region 控制目标表格
        ReportTable table = targetDetailService.getReportWeekTargets(patientId, null, null);
        formInfo.setControlTargetTable(table);
        //endregion
        return formInfo;
    }

    /**
     * @param request
     * @return
     * @deprecated use V3
     */
    @Override
    public PatientIndexFormInfo getPatientIndexFormInfoV2(PatientIndexRequest request) {
        Integer patientId = request.getPatientId();
        PatientIndexFormInfo formInfo = new PatientIndexFormInfo();
        //region 打卡率和达标率
        Date startDate = request.getStartDate();
        Date endDate = request.getEndDate();
        SigninRateLine rate = getFinishedAndReachStandardRate(patientId, startDate, endDate);
        formInfo.setSigninRateLine(rate);
        log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request] formInfo.getSigninRecords()=" + formInfo.getSigninRecords());
        //endregion

        //region 当日打卡
        Date queryDate = request.getQueryDate();
        String startDateStr = DateUtil.formatDate(queryDate);

        SigninRecord signinRecord = signinRecordService.getSigninRecordByPatientIdAndDate(patientId, startDateStr);
        if (signinRecord != null && CollectionUtil.isNotEmpty(signinRecord.getSignInActionList())) {
            List<SignInAction> actionList = signinRecord.getSignInActionList();
            DailyGroupCheckinRecord record = new DailyGroupCheckinRecord();
            record.setPatientId(patientId);
            record.setRecordDate(startDateStr);
            actionList.stream()
                    .peek(po -> {
                        // 处理未配置和未打卡项
                        Integer isDone = Optional.ofNullable(po.getIsDone()).orElse(RecordState.TO_BE_RECORD.getState());
                        Integer signinItemPlanStatus = SigninItemPlanStatus.valueOfRecordState(isDone);
                        if (StringUtils.isEmpty(po.getStarttime()) || StringUtils.isEmpty(po.getEndtime())) {
                            // 未配置
                            signinItemPlanStatus = SigninItemPlanStatus.NOPLAN.getType();
                        }
                        if (signinItemPlanStatus == SigninItemPlanStatus.NOPLAN.getType()) {
                            po.setSigninItemValue(SigninItemPlanStatus.NOPLAN.getStatus());
                        }
                        po.setSigninItemPlanStatus(signinItemPlanStatus);
                    })
                    .forEach(po -> {
                        Integer signinItemPlanStatus = po.getSigninItemPlanStatus();
                        Constant.RecordType recordType = Constant.RecordType.valueOf(po.getRecordType());
                        Integer subType = po.getSubType();
                        if (recordType != null) {
                            switch (recordType) {
                                case SUGAR: {
                                    String recordValue = Optional.ofNullable(wrapper(po.getDataId(), sugarRecordService)).map(DtrdEntRdSigninSugarValue::getSugarValueSugarValue).map(value -> value + "").orElse(po.getSigninItemValue());
                                    if (subType == Constant.SugarRecordType.BEFOREBREAKFAST.getType()) {
                                        record.setK1(recordValue);
                                        record.setK1PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.AFTERBREAKFAST.getType()) {
                                        record.setK2(recordValue);
                                        record.setK2PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.BEFORELUNCH.getType()) {
                                        record.setK3(recordValue);
                                        record.setK3PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.AFTERLUNCH.getType()) {
                                        record.setK4(recordValue);
                                        record.setK4PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.BEFOREDINNER.getType()) {
                                        record.setK5(recordValue);
                                        record.setK5PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.AFTERDINNER.getType()) {
                                        record.setK6(recordValue);
                                        record.setK6PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.EARLYMORNING.getType()) {
                                        record.setK7(recordValue);
                                        record.setK7PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.SugarRecordType.BEFORESLEEP.getType()) {
                                        record.setK8(recordValue);
                                        record.setK8PlanState(signinItemPlanStatus);
                                    }
                                }
                                break;
                                case BLOOD_PRESSURE: {
                                    DtrdEntRdSigninBloodPressure bloodPressurePO = wrapper(po.getDataId(), bloodPressureRecordService);
                                    if (subType == Constant.BloodPressureRecordType.MORNING.getType()) {
                                        record.setK25(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure).map(value -> value + "").orElse(po.getSigninItemValue()));
                                        record.setK26(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureLowVoltage).map(value -> value + "").orElse(po.getSigninItemValue()));
                                        record.setK27(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHeartRate).map(value -> value + "").orElse(po.getSigninItemValue()));
                                        record.setK25PlanState(signinItemPlanStatus);
                                        record.setK26PlanState(signinItemPlanStatus);
                                        record.setK27PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.BloodPressureRecordType.EVENING.getType()) {
                                        record.setK28(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure).map(value -> value + "").orElse(po.getSigninItemValue()));
                                        record.setK29(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure).map(value -> value + "").orElse(po.getSigninItemValue()));
                                        record.setK30(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure).map(value -> value + "").orElse(po.getSigninItemValue()));
                                        record.setK28PlanState(signinItemPlanStatus);
                                        record.setK29PlanState(signinItemPlanStatus);
                                        record.setK30PlanState(signinItemPlanStatus);
                                    }
                                }
                                break;
                                case SPORT:
                                    DtrdEntRdSigninSportRecord sportRecord = wrapper(po.getDataId(), sportRecordService);
                                    record.setK12(Optional.ofNullable(sportRecord).map(DtrdEntRdSigninSportRecord::getRecordPhoto).orElse(po.getSigninItemValue()));
                                    record.setK12PlanState(signinItemPlanStatus);
                                    record.setK12Describe(Optional.ofNullable(sportRecord).map(DtrdEntRdSigninSportRecord::getSportRecordPowerDescribe).orElse(po.getSigninItemValue()));
                                    break;
                                case MEDICAL: {
                                    DtrdEntRdSigninMedicalRecord medicalRecord = wrapper(po.getDataId(), medicalRecordService);
                                    if (subType == Constant.MedicalRecordType.MORNING.getType()) {
                                        record.setK13(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
                                        record.setK13Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
                                        record.setK13PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
                                        record.setK14(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
                                        record.setK14Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
                                        record.setK14PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
                                        record.setK15(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
                                        record.setK15Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
                                        record.setK15PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
                                        record.setK16(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
                                        record.setK16Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
                                        record.setK16PlanState(signinItemPlanStatus);
                                    }
                                }
                                break;
                                case DIET: {
                                    DtrdEntRdSigninFoodRecord foodRecord = wrapper(po.getDataId(), foodRecordService);
                                    if (subType == Constant.FoodRecordType.BREAKFAST.getType()) {
                                        record.setK9(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
                                        record.setK9Describe(po.getSigninItemValue());
                                        record.setK9PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.FoodRecordType.LUNCH.getType()) {
                                        record.setK10(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
                                        record.setK10Describe(po.getSigninItemValue());
                                        record.setK10PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.FoodRecordType.DINNER.getType()) {
                                        record.setK11(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
                                        record.setK11Describe(po.getSigninItemValue());
                                        record.setK11PlanState(signinItemPlanStatus);
                                    }
                                }
                                break;
                                case WEIGHT:
                                    DtrdEntRdSigninHeightWeight heightWeight = wrapper(po.getDataId(), heightWeightRecordService);
                                    record.setK22(Optional.ofNullable(heightWeight).map(DtrdEntRdSigninHeightWeight::getHeightWeightWeight).map(value -> value + "").orElse(po.getSigninItemValue()));
                                    record.setK22PlanState(signinItemPlanStatus);
                                    break;
                                case WAIST:
                                    DtrdEntRdSigninWaistline waist = wrapper(po.getDataId(), waistlineRecordService);
                                    record.setK24(Optional.ofNullable(waist).map(DtrdEntRdSigninWaistline::getWaistlineValue).map(value -> value + "").orElse(po.getSigninItemValue()));
                                    record.setK24PlanState(signinItemPlanStatus);
                                    break;
                                case KETONE:
                                    DtrdEntRdSigninKetone ketone = wrapper(po.getDataId(), ketoneRecordService);
                                    record.setK23(Optional.ofNullable(ketone).map(DtrdEntRdSigninKetone::getRecordPhoto).orElse(null));
                                    record.setK23PlanState(signinItemPlanStatus);
                                    break;
                                case INSULIN: {
                                    DtrdEntRdSigninInsulin insulin = wrapper(po.getDataId(), insulinRecordService);
                                    if (subType == Constant.InsulinRecordType.MORNING.getType()) {
                                        record.setK17(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
                                        record.setK17Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
                                        record.setK17PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
                                        record.setK18(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
                                        record.setK18Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
                                        record.setK18PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
                                        record.setK19(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
                                        record.setK19Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
                                        record.setK19PlanState(signinItemPlanStatus);
                                    } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
                                        record.setK20(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
                                        record.setK20Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
                                        record.setK20PlanState(signinItemPlanStatus);
                                    }
                                }
                                break;
                                case SLEEP:
                                    DtrdEntRdSigninSleep sleep = wrapper(po.getDataId(), sleepRecordService);
                                    record.setK21(Optional.ofNullable(sleep).map(DtrdEntRdSigninSleep::getSleepStatus).map(SleepStatus::valueOf).map(SleepStatus::getSleepStatusDesc).orElse(po.getSigninItemValue()));
                                    record.setK21PlanState(signinItemPlanStatus);
                                    log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request]  sleep k21=" + record.getK21());
                                    break;
                                default:
                                    break;
                            }
                        }
                    });
            formInfo.setSigninRecords(record);
        }
        //endregion

        //region 控制目标表格
        ReportTable table = targetDetailService.getReportWeekTargets(patientId, null, null);
        formInfo.setControlTargetTable(table);
        //endregion
        return formInfo;
    }

    @Override
    public PatientIndexFormInfo getPatientIndexFormInfoV3(PatientIndexRequest request) {
        Integer patientId = request.getPatientId();
        PatientIndexFormInfo formInfo = new PatientIndexFormInfo();
        //region 打卡率和达标率
        Date startDate = request.getStartDate();
        Date endDate = request.getEndDate();
        SigninRateLine rate = getFinishedAndReachStandardRate(patientId, startDate, endDate);
        formInfo.setSigninRateLine(rate);
        log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfo.[request] formInfo.getSigninRecords()=" + formInfo.getSigninRecords());
        //endregion

        //region 当日打卡
        Date queryDate = request.getQueryDate();
        String startDateStr = DateUtil.formatDate(queryDate);
        List<DailyGroupCheckinRecord> records = checkinRecordViewService.getCheckinRecords(patientId, startDateStr, startDateStr, true);

        if (CollectionUtil.isNotEmpty(records)) {
            formInfo.setSigninRecords(records.get(0));
        }
//        SigninRecord signinRecord = signinRecordService.getSigninRecordByPatientIdAndDate(patientId, startDateStr);
//        if (signinRecord != null && CollectionUtil.isNotEmpty(signinRecord.getSignInActionList())) {
//            List<SignInAction> actionList = signinRecord.getSignInActionList();
//            DailyGroupCheckinRecord record = new DailyGroupCheckinRecord();
//            record.setPatientId(patientId);
//            record.setRecordDate(startDateStr);
//            actionList.stream()
//                    .peek(po -> {
//                        // 处理未配置和未打卡项
//                        Integer isDone = Optional.ofNullable(po.getIsDone()).orElse(RecordState.TO_BE_RECORD.getState());
//                        Integer signinItemPlanStatus = SigninItemPlanStatus.valueOfRecordState(isDone);
//                        if (StringUtils.isEmpty(po.getStarttime()) || StringUtils.isEmpty(po.getEndtime())) {
//                            // 未配置
//                            signinItemPlanStatus = SigninItemPlanStatus.NOPLAN.getType();
//                        }
//                        if (signinItemPlanStatus == SigninItemPlanStatus.NOPLAN.getType()) {
//                            po.setSigninItemValue(SigninItemPlanStatus.NOPLAN.getStatus());
//                        }
//                        po.setSigninItemPlanStatus(signinItemPlanStatus);
//                        if (po.getRecordType() == RecordType.SLEEP.getType()) {
//                            log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfoV3.[request] sleep po=" + po);
//                        }
//                    })
//                    .forEach(po -> {
//                        Integer signinItemPlanStatus = po.getSigninItemPlanStatus();
//                        Constant.RecordType recordType = Constant.RecordType.valueOf(po.getRecordType());
//                        Integer subType = po.getSubType();
//                        if (recordType != null) {
//                            String recordValue = po.getRecordValue();
//                            switch (recordType) {
//                                case SUGAR: {
//                                    if (recordValue == null) {
//                                        recordValue = Optional.ofNullable(wrapper(po.getDataId(), sugarRecordService)).map(DtrdEntRdSigninSugarValue::getSugarValueSugarValue).map(value -> value + "").orElse(po.getSigninItemValue());
//                                    }
//                                    if (subType == Constant.SugarRecordType.BEFOREBREAKFAST.getType()) {
//                                        record.setK1(recordValue);
//                                        record.setK1PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.AFTERBREAKFAST.getType()) {
//                                        record.setK2(recordValue);
//                                        record.setK2PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.BEFORELUNCH.getType()) {
//                                        record.setK3(recordValue);
//                                        record.setK3PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.AFTERLUNCH.getType()) {
//                                        record.setK4(recordValue);
//                                        record.setK4PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.BEFOREDINNER.getType()) {
//                                        record.setK5(recordValue);
//                                        record.setK5PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.AFTERDINNER.getType()) {
//                                        record.setK6(recordValue);
//                                        record.setK6PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.EARLYMORNING.getType()) {
//                                        record.setK7(recordValue);
//                                        record.setK7PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.SugarRecordType.BEFORESLEEP.getType()) {
//                                        record.setK8(recordValue);
//                                        record.setK8PlanState(signinItemPlanStatus);
//                                    }
//                                }
//                                break;
//                                case BLOOD_PRESSURE: {
//
////                                    DtrdEntRdSigninBloodPressure bloodPressurePO = wrapper(po.getDataId(), bloodPressureRecordService);
////                                    if (subType == Constant.BloodPressureRecordType.MORNING.getType()) {
////                                        record.setK25(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure).map(value -> value + "").orElse(po.getSigninItemValue()));
////                                        record.setK26(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureLowVoltage).map(value -> value + "").orElse(po.getSigninItemValue()));
////                                        record.setK27(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHeartRate).map(value -> value + "").orElse(po.getSigninItemValue()));
////                                        record.setK25PlanState(signinItemPlanStatus);
////                                        record.setK26PlanState(signinItemPlanStatus);
////                                        record.setK27PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.BloodPressureRecordType.EVENING.getType()) {
////                                        record.setK28(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure).map(value -> value + "").orElse(po.getSigninItemValue()));
////                                        record.setK29(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureLowVoltage).map(value -> value + "").orElse(po.getSigninItemValue()));
////                                        record.setK30(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHeartRate).map(value -> value + "").orElse(po.getSigninItemValue()));
////                                        record.setK28PlanState(signinItemPlanStatus);
////                                        record.setK29PlanState(signinItemPlanStatus);
////                                        record.setK30PlanState(signinItemPlanStatus);
////                                    }
////                                    if (po.getRecordValue() == null) {
////                                        DtrdEntRdSigninBloodPressure bloodPressurePO = wrapper(po.getDataId(), bloodPressureRecordService);
////                                        po.setRecordValue(wrapperValue(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure), po.getSigninItemValue()));
////                                        po.setRecordValue2(wrapperValue(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureLowVoltage), po.getSigninItemValue()));
////                                        po.setRecordValue3(wrapperValue(Optional.ofNullable(bloodPressurePO).map(DtrdEntRdSigninBloodPressure::getBloodPressureHeartRate), po.getSigninItemValue()));
////                                    }
//                                    if (subType == Constant.BloodPressureRecordType.MORNING.getType()) {
//                                        record.setK25(Optional.ofNullable(po.getRecordValue()).orElse(po.getSigninItemValue()));
//                                        record.setK26(Optional.ofNullable(po.getRecordValue2()).orElse(po.getSigninItemValue()));
//                                        record.setK27(Optional.ofNullable(po.getRecordValue3()).orElse(po.getSigninItemValue()));
//                                        record.setK25PlanState(signinItemPlanStatus);
//                                        record.setK26PlanState(signinItemPlanStatus);
//                                        record.setK27PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.BloodPressureRecordType.EVENING.getType()) {
//                                        record.setK28(Optional.ofNullable(po.getRecordValue()).orElse(po.getSigninItemValue()));
//                                        record.setK29(Optional.ofNullable(po.getRecordValue2()).orElse(po.getSigninItemValue()));
//                                        record.setK30(Optional.ofNullable(po.getRecordValue3()).orElse(po.getSigninItemValue()));
//                                        record.setK28PlanState(signinItemPlanStatus);
//                                        record.setK29PlanState(signinItemPlanStatus);
//                                        record.setK30PlanState(signinItemPlanStatus);
//                                    }
//                                }
//                                break;
//                                case SPORT:
////                                    DtrdEntRdSigninSportRecord sportRecord = wrapper(po.getDataId(), sportRecordService);
////                                    record.setK12(Optional.ofNullable(sportRecord).map(DtrdEntRdSigninSportRecord::getRecordPhoto).orElse(po.getSigninItemValue()));
////                                    record.setK12Describe(Optional.ofNullable(sportRecord).map(DtrdEntRdSigninSportRecord::getSportRecordPowerDescribe).orElse(po.getSigninItemValue()));
//                                    if (po.getRecordPhoto() == null) {
//                                        DtrdEntRdSigninSportRecord sportRecord = wrapper(po.getDataId(), sportRecordService);
//                                        po.setRecordPhoto(Optional.ofNullable(sportRecord).map(DtrdEntRdSigninSportRecord::getRecordPhoto).orElse(po.getSigninItemValue()));
//                                        po.setRecordDesc(Optional.ofNullable(sportRecord).map(DtrdEntRdSigninSportRecord::getSportRecordPowerDescribe).orElse(po.getSigninItemValue()));
//                                    }
//                                    record.setK12(Optional.ofNullable(po.getRecordPhoto()).orElse(po.getSigninItemValue()));
//                                    record.setK12Describe(Optional.ofNullable(po.getRecordDesc()).orElse(po.getSigninItemValue()));
//                                    record.setK12PlanState(signinItemPlanStatus);
//                                    break;
//                                case MEDICAL: {
////                                    DtrdEntRdSigninMedicalRecord medicalRecord = wrapper(po.getDataId(), medicalRecordService);
////                                    if (subType == Constant.MedicalRecordType.MORNING.getType()) {
////                                        record.setK13(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
////                                        record.setK13Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
////                                        record.setK13PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
////                                        record.setK14(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
////                                        record.setK14Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
////                                        record.setK14PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
////                                        record.setK15(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
////                                        record.setK15Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
////                                        record.setK15PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
////                                        record.setK16(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
////                                        record.setK16Describe(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
////                                        record.setK16PlanState(signinItemPlanStatus);
////                                    }
//                                    if (po.getRecordPhoto() == null) {
//                                        DtrdEntRdSigninMedicalRecord medicalRecord = wrapper(po.getDataId(), medicalRecordService);
//                                        po.setRecordPhoto(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordPhoto).orElse(null));
//                                        po.setRecordDesc(Optional.ofNullable(medicalRecord).map(DtrdEntRdSigninMedicalRecord::getMedicalRecordStatus).map(status -> status + "").orElse(po.getSigninItemValue()));
//                                    }
//                                    if (subType == Constant.MedicalRecordType.MORNING.getType()) {
//                                        record.setK13(po.getRecordPhoto());
//                                        record.setK13Describe(Optional.ofNullable(po.getRecordValue()).orElse(po.getSigninItemValue()));
//                                        record.setK13PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
//                                        record.setK14(po.getRecordPhoto());
//                                        record.setK14Describe(Optional.ofNullable(po.getRecordValue()).orElse(po.getSigninItemValue()));
//                                        record.setK14PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
//                                        record.setK15(po.getRecordPhoto());
//                                        record.setK15Describe(Optional.ofNullable(po.getRecordValue()).orElse(po.getSigninItemValue()));
//                                        record.setK15PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
//                                        record.setK16(po.getRecordPhoto());
//                                        record.setK16Describe(Optional.ofNullable(po.getRecordValue()).orElse(po.getSigninItemValue()));
//                                        record.setK16PlanState(signinItemPlanStatus);
//                                    }
//                                }
//                                break;
//                                case DIET: {
////                                    DtrdEntRdSigninFoodRecord foodRecord = wrapper(po.getDataId(), foodRecordService);
////                                    if (subType == Constant.FoodRecordType.BREAKFAST.getType()) {
////                                        record.setK9(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
////                                        record.setK9Describe(po.getSigninItemValue());
////                                        record.setK9PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.FoodRecordType.LUNCH.getType()) {
////                                        record.setK10(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
////                                        record.setK10Describe(po.getSigninItemValue());
////                                        record.setK10PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.FoodRecordType.DINNER.getType()) {
////                                        record.setK11(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
////                                        record.setK11Describe(po.getSigninItemValue());
////                                        record.setK11PlanState(signinItemPlanStatus);
////                                    }
//                                    if (po.getRecordPhoto() == null) {
//                                        DtrdEntRdSigninFoodRecord foodRecord = wrapper(po.getDataId(), foodRecordService);
//                                        po.setRecordPhoto(Optional.ofNullable(foodRecord).map(DtrdEntRdSigninFoodRecord::getRecordPhoto).orElse(null));
//                                    }
//                                    if (subType == Constant.FoodRecordType.BREAKFAST.getType()) {
//                                        record.setK9(po.getRecordPhoto());
//                                        record.setK9Describe(po.getSigninItemValue());
//                                        record.setK9PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.FoodRecordType.LUNCH.getType()) {
//                                        record.setK10(po.getRecordPhoto());
//                                        record.setK10Describe(po.getSigninItemValue());
//                                        record.setK10PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.FoodRecordType.DINNER.getType()) {
//                                        record.setK11(po.getRecordPhoto());
//                                        record.setK11Describe(po.getSigninItemValue());
//                                        record.setK11PlanState(signinItemPlanStatus);
//                                    }
//                                }
//                                break;
//                                case WEIGHT:
//                                    recordValue = po.getRecordValue3();
//                                    if (recordValue == null) {
//                                        DtrdEntRdSigninHeightWeight heightWeight = wrapper(po.getDataId(), heightWeightRecordService);
//                                        recordValue = Optional.ofNullable(heightWeight)
//                                                .map(DtrdEntRdSigninHeightWeight::getHeightWeightBmi)
//                                                .map(value -> value + "").orElse(null);
//                                    }
//                                    record.setK22(Optional.ofNullable(recordValue).orElse(po.getSigninItemValue()));
//                                    record.setK22PlanState(signinItemPlanStatus);
//                                    break;
//                                case WAIST:
//                                    if (recordValue == null) {
//                                        DtrdEntRdSigninWaistline waist = wrapper(po.getDataId(), waistlineRecordService);
//                                        recordValue = Optional.ofNullable(waist).map(DtrdEntRdSigninWaistline::getWaistlineValue).map(value -> value + "").orElse(po.getSigninItemValue());
//                                    }
//                                    record.setK24(Optional.ofNullable(recordValue).orElse(po.getSigninItemValue()));
//                                    record.setK24PlanState(signinItemPlanStatus);
//                                    break;
//                                case KETONE:
//                                    if (po.getRecordPhoto() == null) {
//                                        DtrdEntRdSigninKetone ketone = wrapper(po.getDataId(), ketoneRecordService);
//                                        po.setRecordPhoto(Optional.ofNullable(ketone).map(DtrdEntRdSigninKetone::getRecordPhoto).orElse(null));
//                                    }
//                                    record.setK23(po.getRecordPhoto());
//                                    record.setK23Describe(recordValue);
//
//                                    record.setK23PlanState(signinItemPlanStatus);
//                                    break;
//                                case INSULIN: {
////                                    DtrdEntRdSigninInsulin insulin = wrapper(po.getDataId(), insulinRecordService);
////                                    if (subType == Constant.InsulinRecordType.MORNING.getType()) {
////                                        record.setK17(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
////                                        record.setK17Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
////                                        record.setK17PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
////                                        record.setK18(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
////                                        record.setK18Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
////                                        record.setK18PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
////                                        record.setK19(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
////                                        record.setK19Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
////                                        record.setK19PlanState(signinItemPlanStatus);
////                                    } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
////                                        record.setK20(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
////                                        record.setK20Describe(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
////                                        record.setK20PlanState(signinItemPlanStatus);
////                                    }
//
//                                    if (po.getRecordPhoto() == null || po.getRecordValue() == null) {
//                                        DtrdEntRdSigninInsulin insulin = wrapper(po.getDataId(), insulinRecordService);
//                                        po.setRecordPhoto(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getRecordPhoto).orElse(null));
//                                        po.setRecordValue(Optional.ofNullable(insulin).map(DtrdEntRdSigninInsulin::getInsulinInjection).map(value -> value + "").orElse(null));
//                                    }
//
//                                    if (subType == Constant.InsulinRecordType.MORNING.getType()) {
//                                        record.setK17(po.getRecordPhoto());
//                                        record.setK17Describe(po.getRecordValue());
//                                        record.setK17PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.MedicalRecordType.NOON.getType()) {
//                                        record.setK18(po.getRecordPhoto());
//                                        record.setK18Describe(po.getRecordValue());
//                                        record.setK18PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.MedicalRecordType.EVENING.getType()) {
//                                        record.setK19(po.getRecordPhoto());
//                                        record.setK19Describe(po.getRecordValue());
//                                        record.setK19PlanState(signinItemPlanStatus);
//                                    } else if (subType == Constant.MedicalRecordType.SLEEP.getType()) {
//                                        record.setK20(po.getRecordPhoto());
//                                        record.setK20Describe(po.getRecordValue());
//                                        record.setK20PlanState(signinItemPlanStatus);
//                                    }
//                                }
//                                break;
//                                case SLEEP:
////                                    DtrdEntRdSigninSleep sleep = wrapper(po.getDataId(), sleepRecordService);
////                                    record.setK21(Optional.ofNullable(sleep).map(DtrdEntRdSigninSleep::getSleepStatus).map(SleepStatus::valueOf).map(SleepStatus::getSleepStatusDesc).orElse(po.getSigninItemValue()));
//                                    if (po.getRecordValue() == null) {
//                                        DtrdEntRdSigninSleep sleep = wrapper(po.getDataId(), sleepRecordService);
//                                        po.setRecordValue(Optional.ofNullable(sleep).map(DtrdEntRdSigninSleep::getSleepStatus).map(SleepStatus::valueOf).map(SleepStatus::getSleepStatusDesc).orElse(po.getSigninItemValue()));
//                                    }
//                                    record.setK21(Optional.ofNullable(po.getRecordValue())
//                                            .map(StringUtil::StrTrimInt)
//                                            .map(SleepStatus::valueOf).map(SleepStatus::getSleepStatusDesc)
//                                            .orElse(po.getSigninItemValue()));
//                                    record.setK21PlanState(signinItemPlanStatus);
//                                    log.info("DtrdEntRdPatientServiceImpl.getPatientIndexFormInfoV3.[request] sleep k21=" + record.getK21() + "; state=" + record.getK21PlanState());
//                                    break;
//                                default:
//                                    break;
//                            }
//                        }
//                    });
//            formInfo.setSigninRecords(record);
//        }
        //endregion

        //region 控制目标表格
//        ReportTable table = targetDetailService.getReportWeekTargets(patientId, null, null);
        ReportTable table = targetDetailService.getReportWeekTargetsV2(patientId);
        formInfo.setControlTargetTable(table);
        //endregion
        return formInfo;
    }

    private <T> T wrapper(Integer dataId, IRecordService<T> recordService) {
        return Optional.ofNullable(dataId).map(recordService::getById).orElse(null);
    }

    private String wrapperValue(Object value, String defaultValue) {
        return Optional.ofNullable(value).map(String::valueOf).orElse(defaultValue);
    }


    @Override
    public List<DtrdEntRdPatient> listPatientsByIds(List<Integer> patientIds) {
        LambdaQueryWrapper<DtrdEntRdPatient> wrapper = Wrappers.lambdaQuery(DtrdEntRdPatient.class).in(DtrdEntRdPatient::getDataId, patientIds);
        return list(wrapper);
    }

    @Override
    public Map<Integer, String> getPatientIdToNameMap(List<Integer> patientIds) {
        LambdaQueryWrapper<DtrdEntRdPatient> wrapper = Wrappers.lambdaQuery(DtrdEntRdPatient.class).in(DtrdEntRdPatient::getDataId, patientIds);
        List<DtrdEntRdPatient> patients = list(wrapper);
        if (CollectionUtil.isNotEmpty(patients)) {
            Map<Integer, String> map = new HashMap<>(patients.size());
            for (DtrdEntRdPatient patient : patients) {
                map.put(patient.getDataId(), patient.getPatientsName());
            }
            return map;
        }
        return null;
    }

    @Override
    public String getPatientOpenIdByPatientId(Integer patientId) {
        return baseMapper.getPatientOpenIdByPatientId(patientId);
    }

    @Override
    public String generateQrCode(Integer patientId) {
        DtrdEntRdPatient patient = getById(patientId);
        if (patient == null) {
            log.info("DtrdEntRdPatientServiceImpl.generateQrCode.[patientId] patientId= " + patientId + ";  patient not found ");
            return null;
        }
        sendQrCodeGenerateEvent(patient, true);
        log.info("DtrdEntRdPatientServiceImpl.generateQrCode.[patientId] after send getWxOaQrcodeUrl = " + patient.getWxOaQrcodeUrl());
        return patient.getWxOaQrcodeUrl();
    }

    @Override
    public IPage<PatientInfo> getAllPatients(PatientAllRequest request) {
        LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdPatient.class);
        if (request.getPatientName() != null) {
            queryWrapper.like(DtrdEntRdPatient::getPatientsName, request.getPatientName());
        }
        if (request.getPatientMobile() != null) {
            queryWrapper.like(DtrdEntRdPatient::getPatientsMobile, request.getPatientMobile());
        }
        queryWrapper.orderByDesc(DtrdEntRdPatient::getDataId);
        IPage<DtrdEntRdPatient> page = new Page<>(request.getPageNum(), request.getPageSize());
        page = page(page, queryWrapper);
        return page.convert(po -> {
            PatientInfo patientInfo = new PatientInfo().parseFromPO(po);
            if (po.getDoctorId() != null) {
                String doctorName = Optional.ofNullable(po.getDoctorId()).map(id -> doctorService.getById(id)).map(DtrdEntRdDoctor::getDoctorsName).orElse(null);
                patientInfo.setDoctorName(doctorName);
            }
            return patientInfo;
        });
    }

    @Override
    public BasePatientInfo getPatientBaseInfo(Integer patientId) {
        BasePatientInfo info = baseMapper.getPatientBaseInfo(patientId);
        if (info != null) {
            DtrdEntRdArchiveBasic basicInfo = basicService.getPatientBasicInfoByPatientId(patientId);
            info.setPatientsDescription(Optional.ofNullable(basicInfo).map(DtrdEntRdArchiveBasic::getPatientDescription).orElse(null));
        }
        return info;
    }

    private SigninRateLine getFinishedAndReachStandardRate(Integer patientId, Date startDate, Date endDate) {
        Map<Date, Integer> finishedRateMap = signinRecordService.getSigninFinishedRateMap(patientId, startDate, endDate);
        Map<Date, Integer> reachStandardMap = uplowRecordService.getSugarReachStandard(patientId, startDate, endDate);
        if (MapUtil.isNotEmpty(finishedRateMap) || MapUtil.isNotEmpty(reachStandardMap)) {
            return ReportUtil.getFinishedAndReachStandardRate(startDate, endDate, finishedRateMap, reachStandardMap);
        }
        return null;
    }


    private PatientInfo selectOne(LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper) {
        queryWrapper.orderByAsc(DtrdEntRdPatient::getCreateTime);
        queryWrapper.last("limit 1");
        DtrdEntRdPatient dtrdEntRdPatient = baseMapper.selectOne(queryWrapper);
        if (dtrdEntRdPatient != null) {
            PatientInfo patientInfo = new PatientInfo().parseFromPO(dtrdEntRdPatient);
            patientInfo.setPatientsDiabetisTypeName(queryDictTextByKey(DIABETIS_TYPE, patientInfo.getPatientsDiabetisType()));
            patientInfo.setPatientsMedicalInsuranceName(queryDictTextByKey(INSURANCE, patientInfo.getPatientsMedicalInsurance()));
            patientInfo.setPatientsModeOnsetName(queryDictTextByKey(SYMPTOMSMODE, patientInfo.getPatientsModeOnset()));
            patientInfo.setPatientsDiagnosticName(formatMultiDicode(DIAGNOSIS, patientInfo.getPatientsDiagnostic()));
            patientInfo.setPatientsSymptomsName(formatMultiDicode(SYMPTOMS, patientInfo.getPatientsSymptoms()));
            return patientInfo;
        }
        return null;
    }

    private DtrdEntRdPatient selectOnePo(LambdaQueryWrapper<DtrdEntRdPatient> queryWrapper) {
        queryWrapper.orderByAsc(DtrdEntRdPatient::getCreateTime);
        queryWrapper.last("limit 1");
        return baseMapper.selectOne(queryWrapper);
    }

    private LambdaQueryWrapper<DtrdEntRdPatient> generateBaseLambdaQuery() {
        LambdaQueryWrapper<DtrdEntRdPatient> query = new LambdaQueryWrapper<>();
        query.eq(DtrdEntRdPatient::getIsDel, 0);
        return query;
    }

    private String formatMultiDicode(String dictCode, String keys) {
        if (CheckUtil.isNotEmpty(keys)) {
            String[] split = keys.split(COMMA);
            StringBuilder sb = new StringBuilder();
            IntStream.range(0, split.length).forEach(i -> {
                sb.append(queryDictTextByKey(dictCode, split[i]));
                if (i < split.length - 1) {
                    sb.append(COMMA);
                }
            });
            return sb.toString();
        }
        return null;
    }

    private String queryDictTextByKey(String dictCode, Object dictKey) {
        if (dictKey != null) {
            return sysDictService.queryDictTextByKey(dictCode, dictKey + "");
        } else {
            return null;
        }
    }


}
